package io.gitee.zhangbinhub.acp.core.packet.iso8583

import io.gitee.zhangbinhub.acp.core.common.CommonTools
import io.gitee.zhangbinhub.acp.core.common.exceptions.ConfigException
import io.gitee.zhangbinhub.acp.core.common.log.LogFactory
import java.io.File
import java.io.FileInputStream
import java.io.IOException
import java.io.InputStreamReader
import java.lang.reflect.InvocationTargetException
import java.util.*
import java.util.concurrent.ConcurrentHashMap

/**
 * @since JDK 17
 */
class Iso8583FieldProperties : Properties() {
    var fileAbsPathName: String = ""
    private var lastModified: Long = 0

    companion object {

        private val log = LogFactory.getInstance(Iso8583FieldProperties::class.java)
        private val instanceMap: MutableMap<String, Iso8583FieldProperties?> = ConcurrentHashMap()

        /**
         * 获取数据库配置实例
         *
         * @return 数据库配置实例
         */
        @JvmStatic
        fun getInstance(): Iso8583FieldProperties? =
            try {
                val propertiesFileName = "${CommonTools.getWebRootAbsPath()}/iso8583.properties"
                getInstance(
                    Iso8583FieldProperties::class.java,
                    propertiesFileName,
                    propertiesFileName
                )
            } catch (e: Exception) {
                log.error(e.message, e)
                null
            }

        @Throws(
            ConfigException::class,
            IOException::class,
            IllegalAccessException::class,
            InstantiationException::class,
            NoSuchMethodException::class,
            InvocationTargetException::class
        )
        private fun getInstance(
            cls: Class<Iso8583FieldProperties>,
            propertiesFileName: String,
            fileAbsPathName: String?
        ): Iso8583FieldProperties? {
            return if (!CommonTools.isNullStr(propertiesFileName)) {
                val filePath = if (CommonTools.isNullStr(fileAbsPathName)) {
                    propertiesFileName
                } else {
                    fileAbsPathName!!.replace("/", File.separator).replace("\\", File.separator)
                }
                val file = File(filePath)
                var inputStreamReader: InputStreamReader? = null
                if (!file.exists()) {
                    val input = CommonTools.getResourceInputStream(propertiesFileName.replace("\\", "/"))
                    if (input != null) {
                        inputStreamReader = InputStreamReader(input, CommonTools.getDefaultCharsetName())
                    } else {
                        log.warn("$propertiesFileName is not found")
                    }
                } else {
                    inputStreamReader = InputStreamReader(FileInputStream(file), CommonTools.getDefaultCharsetName())
                }
                var instance = instanceMap[propertiesFileName]
                if (!instanceMap.containsKey(propertiesFileName) || file.exists() && file.lastModified() > instance!!.lastModified) {
                    if (inputStreamReader != null) {
                        synchronized(instanceMap) {
                            instance = cls.getDeclaredConstructor().newInstance()
                            instance!!.load(inputStreamReader)
                            if (file.exists()) {
                                instance.lastModified = file.lastModified()
                            }
                            instance.fileAbsPathName = file.canonicalPath
                            instanceMap[propertiesFileName] = instance
                            log.info("load [" + propertiesFileName + "] success => " + cls.canonicalName)
                            return instance
                        }
                    } else {
                        null
                    }
                } else {
                    instance
                }
            } else {
                throw ConfigException("load config failed : need specify properties file for [" + cls.canonicalName + "]")
            }
        }
    }
}
